package com.lyncs.ods.common.web;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.ttl.TransmittableThreadLocal;
import com.lyncs.ods.common.exception.ApiException;
import com.lyncs.ods.constant.LanguageEnum;
import com.lyncs.ods.constant.LyncsOdsConstant;
import com.lyncs.ods.security.util.JwtTokenUtil;
import io.swagger.annotations.ApiImplicitParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: alex
 * @Description:
 * @Date: Create in 2020/1/15 09:51
 */
@Component
@Slf4j
public class RequestHolder {
    private static final TransmittableThreadLocal<Map<String, Object>> THREAD_LOCAL = new TransmittableThreadLocal<>();

    private static JwtTokenUtil jwtTokenUtil;
    private static HttpServletRequest request;

    @Autowired
    private void autowiredService(JwtTokenUtil autowiredJwtTokenUtil,
                                  HttpServletRequest autowiredRequest) {
        jwtTokenUtil = autowiredJwtTokenUtil;
        request = autowiredRequest;
    }

    public static LocalDateTime getRequestDateTime() {
        return getData(LyncsOdsConstant.Header.REQUEST_TIME);
    }

    public static Long getUserId() {
        return jwtTokenUtil.getUserIdFromToken(getToken());
    }

    public static String getOpenId() {
        return jwtTokenUtil.getOpenIdFromToken(getToken());
    }

    public static String getAuthType() {
        return jwtTokenUtil.getAuthTypeFromToken(getToken());
    }

    public static String getCookie() {
        return getData(LyncsOdsConstant.Header.COOKIE);
    }

    public static Map<String, String> getCookieMap() {
        String cookie = getCookie();
        if (StringUtils.isEmpty(cookie)) {
            return new HashMap<>();
        }
        return Arrays.stream(cookie.split(LyncsOdsConstant.Common.SEMICOLON)).filter(Objects::nonNull)
                .collect(Collectors.toMap(i -> i.split(LyncsOdsConstant.Common.COLON)[0], i -> i.split(LyncsOdsConstant.Common.COLON)[1]));
    }

    public static void removeCookie() {
        setData(LyncsOdsConstant.Header.COOKIE, null);
    }

    public static String getToken() {
        return getData(LyncsOdsConstant.Header.COOKIE_PT);
    }

    public static String getPlatform() {
        return getData(LyncsOdsConstant.Header.AUTH_PLATFORM);
    }

    public static Long getCompanyIdAllowNull() {
        String companyId = getData(LyncsOdsConstant.Header.COOKIE_PC);
        return StringUtils.isBlank(companyId) ? null : Long.valueOf(companyId);
    }

    public static Long getCompanyId() {
        String companyId = getData(LyncsOdsConstant.Header.COOKIE_PC);
        if (companyId == null) {
            throw new ApiException("用户未选择登录企业");
        }
        return Long.valueOf(companyId);
    }

    public static Boolean isAdmin() {
        String roleId = getData(LyncsOdsConstant.Header.COOKIE_ROLE);
        return StringUtils.isNotEmpty(roleId) && LyncsOdsConstant.CompanyRole.ADMIN.getKey().equals(Integer.valueOf(roleId));
    }

    private static Map<String, Object> init() {
        Map<String, Object> map = new HashMap<>(16);
        THREAD_LOCAL.set(map);
        return map;
    }

    public static void remove() {
        THREAD_LOCAL.remove();
    }

    public static Map<String, Object> map() {
        Map<String, Object> map = THREAD_LOCAL.get();
        if (CollectionUtil.isEmpty(map)) {
            map = init();
        }
        return map;
    }

    public static <T> void setData(String key, T t) {
        map().put(key, t);
    }

    public static <T> T getData(String key) {
        Object obj = map().get(key);
        return obj == null ? null : (T) obj;
    }

    public static void setHeader(Map<String, List<String>> header) {
        setData("header", header);
    }

    public static String getCookie(String key) {
        Map<String, String> cookieMap = getCookieMap();
        return cookieMap.getOrDefault(key, null);
    }

    public static void saveCookie(String key, String val) {
        Map<String, String> cookieMap = getCookieMap();
        cookieMap.put(key, val);
        setData(key, val);
        String cookie = cookieMap.entrySet().stream()
                .map(entry -> StringUtils.join(entry.getKey(), LyncsOdsConstant.Common.COLON, entry.getValue()))
                .collect(Collectors.joining(LyncsOdsConstant.Common.SEMICOLON));
        saveCookie(cookie);
    }

    public static void saveCookie(String cookie) {
        setData(LyncsOdsConstant.Header.COOKIE, cookie);
    }

    public static Map<String, List<String>> getHeader() {
        Map<String, List<String>> header = getData("header");
        if (CollectionUtil.isEmpty(header)) {
            return Map.of();
        }
        return header;
    }

    /**
     * 根据key取值，大部分场景只取第一个值
     *
     * @param key
     * @return
     */
    public static String header(String key) {
        return header(key, StringUtils.EMPTY);
    }

    public static String header(String key, String defaultVal) {
        List<String> list = headers(key, List.of(defaultVal));
        return CollectionUtil.isNotEmpty(list) ? list.get(0) : defaultVal;
    }

    public static List<String> headers(String key, List<String> defaultVal) {
        Map<String, List<String>> header = getHeader();
        key = key.toLowerCase();
        return header.getOrDefault(key, defaultVal);
    }

    public static String language() {
        //zh-CN,zh-HK,en-US
        String language = getData(LyncsOdsConstant.Header.LANGUAGE);
        return StringUtils.isEmpty(language) ? LanguageEnum.ZH_CN.getLanguage() : language;
    }

}
